package cn.jiaqiang.chatgpt.data.infrastructure.repository;


import cn.jiaqiang.chatgpt.data.domain.order.model.aggregates.CreateOrderAggregate;
import cn.jiaqiang.chatgpt.data.domain.order.model.entity.*;
import cn.jiaqiang.chatgpt.data.domain.order.model.valobj.OrderStatusVO;
import cn.jiaqiang.chatgpt.data.domain.order.model.valobj.PayStatusVO;
import cn.jiaqiang.chatgpt.data.domain.order.repository.IOrderRepository;
import cn.jiaqiang.chatgpt.data.domain.snow.SnowflakeIdGenerator;
import cn.jiaqiang.chatgpt.data.infrastructure.dao.IOpenAIOrderDao;
import cn.jiaqiang.chatgpt.data.infrastructure.dao.IOpenAIProductDao;
import cn.jiaqiang.chatgpt.data.infrastructure.dao.IUserAccountDao;
import cn.jiaqiang.chatgpt.data.infrastructure.dao.IUserModelDao;
import cn.jiaqiang.chatgpt.data.infrastructure.po.OpenAIOrderPO;
import cn.jiaqiang.chatgpt.data.infrastructure.po.OpenAIProductPO;
import cn.jiaqiang.chatgpt.data.infrastructure.po.UserAccountPO;
import cn.jiaqiang.chatgpt.data.infrastructure.po.UserModelPO;
import cn.jiaqiang.chatgpt.data.types.enums.OpenAIProductEnableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Fuzhengwei bugstack.cn @小傅哥
 * @description 订单仓储服务
 * @create 2023-10-05 13:25
 */
@Repository
public class OrderRepository implements IOrderRepository {

    private static final Logger log = LoggerFactory.getLogger(OrderRepository.class);
    @Resource
    private SnowflakeIdGenerator snowflakeIdGenerator;

    @Resource
    private IOpenAIOrderDao openAIOrderDao;
    @Resource
    private IOpenAIProductDao openAIProductDao;
    @Resource
    private IUserAccountDao userAccountDao;
    @Resource
    private IUserModelDao userModelDao;

    @Override
    public UnpaidOrderEntity queryUnpaidOrder(ShopCartEntity shopCartEntity) {
        // 订单持久化对象
        OpenAIOrderPO openAIOrderPOReq = new OpenAIOrderPO();
        openAIOrderPOReq.setOpenid(shopCartEntity.getOpenid());
        openAIOrderPOReq.setProductId(shopCartEntity.getProductId());
                                                    /** <!-- queryUnpaidOrder 查询未支付订单 --> */
        OpenAIOrderPO openAIOrderPORes = openAIOrderDao.queryUnpaidOrder(openAIOrderPOReq);

        if (null == openAIOrderPORes) {
            // 该用户对于该商品, 没有未支付订单, 返回 null 即可.
            return null;
        }
        // 存在未支付订单, 返回该订单信息
        return UnpaidOrderEntity.builder()
                .openid(shopCartEntity.getOpenid())
                .orderId(openAIOrderPORes.getOrderId())
                .productName(openAIOrderPORes.getProductName())
                .totalAmount(openAIOrderPORes.getTotalAmount())
                .payUrl(openAIOrderPORes.getPayUrl())
                .payStatus(PayStatusVO.get(openAIOrderPORes.getPayStatus()))
                .build();
    }

    @Override
    public ProductEntity queryProduct(Integer productId) {
        OpenAIProductPO openAIProductPO = openAIProductDao.queryProductByProductId(productId);
        ProductEntity productEntity = new ProductEntity();
        productEntity.setProductId(openAIProductPO.getProductId());
        productEntity.setProductName(openAIProductPO.getProductName());
        productEntity.setProductDesc(openAIProductPO.getProductDesc());
        productEntity.setQuota(openAIProductPO.getQuota());
        productEntity.setPrice(openAIProductPO.getPrice());
        productEntity.setProductModel(openAIProductPO.getProductModel());
        productEntity.setEnable(OpenAIProductEnableModel.get(openAIProductPO.getIsEnabled()));
        return productEntity;
    }

    @Override
    public void saveOrder(CreateOrderAggregate aggregate) {
        // 用户 openId
        String openid = aggregate.getOpenid();
        // 商品实体
        ProductEntity product = aggregate.getProduct();
        // 订单实体
        OrderEntity order = aggregate.getOrder();
        // 订单持久化实体
        OpenAIOrderPO openAIOrderPO = new OpenAIOrderPO();
        openAIOrderPO.setOpenid(openid);
        openAIOrderPO.setProductId(product.getProductId());
        openAIOrderPO.setProductName(product.getProductName());
        openAIOrderPO.setProductQuota(product.getQuota());
        openAIOrderPO.setOrderId(order.getOrderId());
        openAIOrderPO.setOrderTime(order.getOrderTime());
        openAIOrderPO.setOrderStatus(order.getOrderStatus().getCode());
        openAIOrderPO.setTotalAmount(order.getTotalAmount());
        openAIOrderPO.setPayType(order.getPayTypeVO().getCode());
        openAIOrderPO.setPayStatus(PayStatusVO.WAIT.getCode());
        openAIOrderPO.setProductModel(product.getProductModel());

        /** <!-- 插入订单 --> */
        log.info("订单: {}", openAIOrderPO.toString());
        openAIOrderDao.insert(openAIOrderPO);
    }

    /**
     * 更新订单支付信息
     * @param payOrderEntity 支付单实体
     */
    @Override
    public void updateOrderPayInfo(PayOrderEntity payOrderEntity) {
        // 构造支付持久化实体
        OpenAIOrderPO openAIOrderPO = new OpenAIOrderPO();
        openAIOrderPO.setOpenid(payOrderEntity.getOpenid());
        openAIOrderPO.setOrderId(payOrderEntity.getOrderId());
        openAIOrderPO.setPayUrl(payOrderEntity.getPayUrl());
        // 等待支付
        openAIOrderPO.setPayStatus(payOrderEntity.getPayStatus().getCode());
        openAIOrderDao.updateOrderPayInfo(openAIOrderPO);
    }

    /**
     * 变更: 订单支付成功
     * @param orderId 订单id
     * @param transactionId 交易单号
     * @param totalAmount 总金额
     * @param payTime 支付时间
     */
    @Override
    public boolean changeOrderPaySuccess(String orderId, String transactionId, BigDecimal totalAmount, Date payTime) {
        // 创建订单持久化对象
        OpenAIOrderPO openAIOrderPO = new OpenAIOrderPO();
        openAIOrderPO.setOrderId(orderId); // 订单id
        openAIOrderPO.setPayAmount(totalAmount); // 总金额
        openAIOrderPO.setPayTime(payTime); // 支付时间
        openAIOrderPO.setTransactionId(transactionId); // 交易单号
        int count = openAIOrderDao.changeOrderPaySuccess(openAIOrderPO);
        return count == 1;
    }

    @Override
    public CreateOrderAggregate queryOrder(String orderId) {
        OpenAIOrderPO openAIOrderPO = openAIOrderDao.queryOrder(orderId);

        ProductEntity product = new ProductEntity();
        product.setProductId(openAIOrderPO.getProductId());
        product.setProductName(openAIOrderPO.getProductName());

        OrderEntity order = new OrderEntity();
        order.setOrderId(openAIOrderPO.getOrderId());
        order.setOrderTime(openAIOrderPO.getOrderTime());
        order.setOrderStatus(OrderStatusVO.get(openAIOrderPO.getOrderStatus()));
        order.setTotalAmount(openAIOrderPO.getTotalAmount());

        CreateOrderAggregate createOrderAggregate = new CreateOrderAggregate();
        createOrderAggregate.setOpenid(openAIOrderPO.getOpenid());
        createOrderAggregate.setOrder(order);
        createOrderAggregate.setProduct(product);

        return createOrderAggregate;
    }

    /**
     * 订单商品发货:
     *  1. rollbackFor = Exception.class: 指定了当发生 Exception 及其子类异常时，进行事务回滚。
     *      也就是说，当方法中抛出 Exception 及其子类异常时，事务会回滚。
     *  2. timeout = 350: 指定了事务的超时时间为 350 秒。如果事务执行时间超过这个时间，事务将被回滚。
     *  3. propagation = Propagation.REQUIRED: 指定了事务的传播行为为 REQUIRED。这表示如果当前方法已经在一个事务中运行，
     *     那么该方法将加入到现有的事务中；如果当前方法没有在事务中运行，那么将开启一个新的事务。
     *     这样可以确保多个操作在同一个事务中执行，保证数据的一致性。
     *  4. isolation = Isolation.DEFAULT: 指定了事务的隔离级别为默认级别,数据库默认的隔离级别
     *
     * @param orderId 订单ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 350, propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void deliverGoods(String orderId) {
        // 0. 根据 id 查询订单持久化对象
        OpenAIOrderPO openAIOrderPO = openAIOrderDao.queryOrder(orderId);
        // 1. 变更发货状态
        int updateOrderStatusDeliverGoodsCount = openAIOrderDao.updateOrderStatusDeliverGoods(orderId);
        if (1 != updateOrderStatusDeliverGoodsCount) {
            throw new RuntimeException("updateOrderStatusDeliverGoodsCount update count is not equal 1");
        }

        // 2. 账户额度变更
        // 2.1 新建一个用户持久化对象, 用于更新账户额度
        UserAccountPO userAccountPOReq = new UserAccountPO();
        userAccountPOReq.setId(snowflakeIdGenerator.nextId());
        userAccountPOReq.setOpenid(openAIOrderPO.getOpenid());
        userAccountPOReq.setTotalQuota(openAIOrderPO.getProductQuota());
        userAccountPOReq.setSurplusQuota(openAIOrderPO.getProductQuota());

        // 2.2 根据 openid 查询用户持久化对象
        UserAccountPO userAccountPO = userAccountDao.queryUserAccount(openAIOrderPO.getOpenid());
        log.info("用户信息: {}", userAccountPO.toString());
        if (null != userAccountPO) {
            // 更新额度
            log.info("开始更新用户 openId = {} 额度...", openAIOrderPO.getOpenid());
            int addAccountQuotaCount = userAccountDao.addAccountQuota(userAccountPOReq);
            if (1 != addAccountQuotaCount) {
                throw new RuntimeException("addAccountQuotaCount update count is not equal 1");
            }
            // 更新模型
            UserModelPO userModelPO = userModelDao
                    .queryUserModelPOWithUserIdModel(userAccountPO.getUserId(), openAIOrderPO.getProductModel());
            if (userModelPO == null) {
                // 第一次购买
                userModelPO = UserModelPO.builder()
                        .userId(userAccountPO.getUserId())
                        .model(openAIOrderPO.getProductModel())
                        .quota(openAIOrderPO.getProductQuota())
                        .build();
                userModelDao.insertModelPO(userModelPO);
            } else {
                // 第 n 次购买
                userModelPO.setQuota(userModelPO.getQuota() + openAIOrderPO.getProductQuota());
                userModelDao.updateModelPO(userModelPO);
            }
            log.info("用户 openId = {} 额度更新完成!", openAIOrderPO.getOpenid());
        } else {
            log.error("用户 openId = {} 不存在, 用户额度更新失败!", openAIOrderPO.getOpenid());
        }
    }

    /**
     * 查询待补货订单
     */
    @Override
    public List<String> queryReplenishmentOrder() {
        return openAIOrderDao.queryReplenishmentOrder();
    }

    @Override
    public List<String> queryNoPayNotifyOrder() {
        return openAIOrderDao.queryNoPayNotifyOrder();
    }

    /**
     * 查询超时15分钟，未支付订单
     */
    @Override
    public List<String> queryTimeoutCloseOrderList() {
        return openAIOrderDao.queryTimeoutCloseOrderList();
    }

    @Override
    public boolean changeOrderClose(String orderId) {
        return openAIOrderDao.changeOrderClose(orderId);
    }

    @Override
    public List<ProductEntity> queryProductList() {
        List<OpenAIProductPO> openAIProductPOList =  openAIProductDao.queryProductList();
        List<ProductEntity> productEntityList = new ArrayList<>(openAIProductPOList.size());
        for (OpenAIProductPO openAIProductPO : openAIProductPOList) {
            ProductEntity productEntity = new ProductEntity();
            productEntity.setProductId(openAIProductPO.getProductId());
            productEntity.setProductName(openAIProductPO.getProductName());
            productEntity.setProductDesc(openAIProductPO.getProductDesc());
            productEntity.setQuota(openAIProductPO.getQuota());
            productEntity.setPrice(openAIProductPO.getPrice());
            productEntityList.add(productEntity);
        }
        return productEntityList;
    }

}
